package cn.anecansaitin.jep.interpreter.evaluators;

import cn.anecansaitin.jep.interpreter.Interpreter;
import cn.anecansaitin.jep.parser.ast.node.expression.*;
import cn.anecansaitin.jep.parser.ast.node.expression.literal.FloatLiteral;
import cn.anecansaitin.jep.types.TypeInfo;

public class FloatEvaluator {
    public static float evaluate(Expression expression) {
        return switch (expression) {
            case Unary unary -> unary(unary);
            case Binary binary -> binary(binary);
            case Ternary ternary -> ternary(ternary);
            case Grouping grouping -> evaluate(grouping.expression());
            case FloatLiteral floatLiteral -> floatLiteral.value();
            default -> throw Interpreter.markError(expression, "未实现的运算符");
        };
    }

    private static float unary(Unary unary) {
        return switch (unary.operator().type()) {
            case UNARY_MINUS -> -evaluate(unary.expression());
            case UNARY_PLUS -> evaluate(unary.expression());
            default -> throw Interpreter.markError(unary, "未实现的运算符");
        };
    }

    private static float binary(Binary binary) {
        return switch (binary.operator().type()) {
            case PLUS -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = IntEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue + evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case LONG -> {
                        long leftValue = LongEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue + evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case FLOAT -> {
                        float leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue + IntEvaluator.evaluate(right);
                            case LONG -> leftValue + LongEvaluator.evaluate(right);
                            case FLOAT -> leftValue + evaluate(right);
                            case CHAR -> leftValue + CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue + evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case MINUS -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = IntEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue - evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case LONG -> {
                        long leftValue = LongEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue - evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case FLOAT -> {
                        float leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue - IntEvaluator.evaluate(right);
                            case LONG -> leftValue - LongEvaluator.evaluate(right);
                            case FLOAT -> leftValue - evaluate(right);
                            case CHAR -> leftValue - CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue - evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case MULTIPLY -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = IntEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue * evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case LONG -> {
                        long leftValue = LongEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue * evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case FLOAT -> {
                        float leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue * IntEvaluator.evaluate(right);
                            case LONG -> leftValue * LongEvaluator.evaluate(right);
                            case FLOAT -> leftValue * evaluate(right);
                            case CHAR -> leftValue * CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue * evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            case DIVIDE -> {
                Expression left = binary.left();
                Expression right = binary.right();

                yield switch (left.resultType()) {
                    case INT -> {
                        int leftValue = IntEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue / evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case LONG -> {
                        long leftValue = LongEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue / evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    case FLOAT -> {
                        float leftValue = evaluate(left);

                        yield switch (right.resultType()) {
                            case INT -> leftValue / IntEvaluator.evaluate(right);
                            case LONG -> leftValue / LongEvaluator.evaluate(right);
                            case FLOAT -> leftValue / evaluate(right);
                            case CHAR -> leftValue / CharEvaluator.evaluate(right);
                            default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        };
                    }
                    case CHAR -> {
                        char leftValue = CharEvaluator.evaluate(left);

                        if (right.resultType() == TypeInfo.FLOAT) {
                            yield leftValue / evaluate(right);
                        } else {
                            throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                        }
                    }
                    default -> throw Interpreter.markError(binary, "无法将" + binary.operator() + "运算符用于" + left.resultType() + "和" + right.resultType());
                };
            }
            default -> throw Interpreter.markError(binary, "未实现的运算符");
        };
    }

    private static float ternary(Ternary ternary) {
        boolean condition = BooleanEvaluator.evaluate(ternary.condition());
        Expression trueExpression = ternary.trueValue();
        Expression falseExpression = ternary.falseValue();

        if (condition) {
            return switch (trueExpression.resultType()) {
                case INT -> IntEvaluator.evaluate(trueExpression);
                case LONG -> LongEvaluator.evaluate(trueExpression);
                case FLOAT -> FloatEvaluator.evaluate(trueExpression);
                case CHAR -> CharEvaluator.evaluate(trueExpression);
                default -> throw Interpreter.markError(ternary, "不支持的表达式结果类型");
            };
        } else {
            return switch (falseExpression.resultType()) {
                case INT -> IntEvaluator.evaluate(falseExpression);
                case LONG -> LongEvaluator.evaluate(falseExpression);
                case FLOAT -> FloatEvaluator.evaluate(falseExpression);
                case CHAR -> CharEvaluator.evaluate(falseExpression);
                default -> throw Interpreter.markError(ternary, "不支持的表达式结果类型");
            };
        }
    }
}
